/***************************************************************************************
 * Copyright 2019 Infineon Technologies AG ( www.infineon.com ).                       *
 * All rights reserved.                                                                *
 *                                                                                     *
 * Licensed  Material-Property of Infineon Technologies AG.                            *
 * This software is made available solely pursuant to the terms of Infineon            *
 * Technologies AG agreement which governs its use. This code and the information      *
 * contained in it are proprietary and confidential to Infineon Technologies AG.       *
 * No person is allowed to copy, reprint, reproduce or publish any part of this code,  *
 * nor disclose its contents to others, nor make any use of it, nor allow or assist    *
 * others to make any use of it - unless by prior Written express authorization of     *
 * Infineon Technologies AG and then only to the extent authorized.                    *
 *                                                                                     *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,            *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,           *
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO       *
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,                 *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY             *
 * WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR            *
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF              *
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                          *
 *                                                                                     *
 ***************************************************************************************/

//#include <stdio.h>
#include "auths_api.h"
#include "auths_config.h"
#include "auths_status.h"
#include "crypto_lib.h"
#include "i2c_bus_command.h"
#include "nvm.h"
#include "helper.h"

extern AuthS_Capability auths_capability;

//extern curve_parameter_t ECC_CURVE_163[1];
extern const mac_t  RESET_PASSWORD;
extern dwordvec_t gf2nReturnZ;
extern dwordvec_t gf2nCheck;
extern uint16_t g_DevAddr;

void test_LscDec(uint8_t lsc_numb)
{
	uint16_t ret;
	uint32_t ul_lsc;
	uint32_t ul_lsc_1;
	uint16_t count = 1;
	uint16_t uw_lsc_DecVal=0;
	
	ret = auths_get_lsc_value(lsc_numb, &ul_lsc);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC%d failed, ret=0x%x\r\n", lsc_numb+1, ret);
		return;
	}else{
		PRINT("Before decreasing, LSC%d = 0x%.8X\r\n", lsc_numb+1, ul_lsc);
		if(ul_lsc==0){			
			return;
		}
	}

	ret = auths_set_lsc_decvalue(lsc_numb, count);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Decrease LSC%d failed, ret=0x%x\r\n", lsc_numb+1, ret);
		return;
	}

	ret = auths_get_lsc_decvalue(&uw_lsc_DecVal);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Get decreasing value failed, ret=0x%x", ret);
		return;
	}else{
		PRINT("decreasing value is 0x%.8X\r\n", uw_lsc_DecVal);
    }

	ret = auths_get_lsc_value(lsc_numb, &ul_lsc_1);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC%d failed, ret=0x%x\r\n", lsc_numb+1, ret);
		return;
	}else{
		PRINT("After decreasing, LSC%d = 0x%.8X\r\n", lsc_numb+1, ul_lsc_1);
	}

}

void test_LscWrite(uint8_t lsc_numb)
{
	//uint8_t data_wr[4];
	uint16_t ret;
	uint32_t	ul_lsc;
	uint32_t	ul_lsc_wr = 0x5678;

	ret = auths_get_lsc_lock_status(lsc_numb);
	if(APP_LSC_NOT_LOCKED!=ret){
		PRINT("Warning: LSC%d locked. ret=0x%x\r\n", lsc_numb+1, ret);
		return;
	}

	// Read LSC before Writing
	ret = auths_get_lsc_value(lsc_numb, &ul_lsc);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC%d failed, ret=0x%x\r\n", lsc_numb+1, ret);
	}else{
		PRINT("Before Writing, LSC%d=0x%.8X\r\n", lsc_numb+1, ul_lsc);
	}

	ret = auths_set_lsc_value(lsc_numb, ul_lsc_wr);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Program LSC%d failed, ret=0x%x\r\n",lsc_numb+1, ret);
	}
	
	delay_ms(NVM_PROGRAMMING_TIME);
	
	// Read LSC after Writing
	ret = auths_get_lsc_value(lsc_numb, &ul_lsc);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC%d failed, ret=0x%x\r\n", lsc_numb+1, ret);
	}else{
		PRINT("After Writing, LSC%d = 0x%.8X\r\n", lsc_numb+1, ul_lsc);
	}

	//final check
	if(ul_lsc != ul_lsc_wr){
		PRINT("Mismatch: LSC%d is expected value\r\n", lsc_numb+1);
	}
}

void test_LscLock(uint8_t lsc_numb)
{
	uint16_t ret;
	uint8_t rd_data;
	uint8_t bit_lsc_en_sts;

	if(lsc_numb == 0){
		bit_lsc_en_sts = BIT_LSC_1_EN_STS;
	}
	else if(lsc_numb == 1){
		bit_lsc_en_sts = BIT_LSC_2_EN_STS;
	}
	else if(lsc_numb == 2){
		bit_lsc_en_sts = BIT_LSC_3_EN_STS;
	}
	else if(lsc_numb == 3){
		bit_lsc_en_sts = BIT_LSC_4_EN_STS;
	}
    else{
        PRINT("Error: Invalid lsc_numb\r\n");
        return;
    }
	
	PRINT("Lock LSC%d.\r\n",lsc_numb+1);

	ret = auths_set_lsc_protection(lsc_numb);
	if(APP_LSC_SUCCESS!=ret){
		PRINT("Error: Set protection, ret=0x%x\r\n", ret);
		return;
	}

	ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_FEAT_STS_1, &rd_data, 1);
	if(AUTHS_SUCCESS != ret){
		PRINT("Error: Read AUTHS_SFR_LSC_KILL_FEAT_STS_1, ret=0x%x\r\n", ret);
		return;
	}else{
		//PRINT("LSC_KILL_FEAT_STATUS_1 = 0x%.2X\r\n",rd_data);
		if(((rd_data >> bit_lsc_en_sts) & 0x01) == 0){
			PRINT("BIT_LSC_%d_EN_STS is not set.\r\n",lsc_numb+1);
		} else{
			PRINT("BIT_LSC_%d_EN_STS is set.\r\n",lsc_numb+1);
		}
	}
}


void test_LscSetZero(uint8_t lsc_numb)
{
	uint16_t ret;
	uint32_t ul_lsc;

	ret = auths_get_lsc_lock_status(lsc_numb);
	if(APP_LSC_LOCKED==ret){
		PRINT("Warning: LSC%d locked. ret=0x%x\r\n", lsc_numb+1, ret);
		return;
	}
	
	// Read LSC before ECC
	ret = auths_get_lsc_value(lsc_numb, &ul_lsc);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC%d failed, ret=0x%x\r\n", lsc_numb+1, ret);
		return;
	}else{
		PRINT("Before setting to 0, LSC%d = 0x%.8X\r\n", lsc_numb+1, ul_lsc);
	}

	PRINT("Set LSC%d to Zero.\r\n",lsc_numb+1);

	ret = auths_set_lsc_zero(lsc_numb);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Set LSC%d to zero, ret=0x%x\r\n", lsc_numb+1, ret);
		return;
	}

	delay_ms(NVM_PROGRAMMING_TIME);

	ret = auths_get_lsc_value(lsc_numb, &ul_lsc);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC%d, ret=0x%x\r\n",lsc_numb+1, ret);
		return;
	}

	//final check
	if(ul_lsc !=0){
		PRINT("Mismatch: LSC%d is not 0 \r\n",lsc_numb+1);
	}
}

void test_LscReset(uint8_t lsc_number)
{
	uint16_t ret;
	uint8_t rd_data[UID_BYTE_LEN];
	//mac_t mac_result;
	//uint8_t mac_byte[MAC_BYTE_LEN];
	uint8_t bit_position;

	ret = auths_get_ecc_kill_status();
	if((ret != APP_ECC_NOTKILLED) || (ret != APP_ECC_KILLED)){
		return;
	}
	if(ret == APP_ECC_KILLED ){
		PRINT("Warning: Unable to reset LSC. Device ECC killed.\r\n");
		return;
	}

	ret = auths_reset_lsc(lsc_number);
	delay_ms(NVM_PROGRAMMING_TIME);
	delay_ms(NVM_PROGRAMMING_TIME);

#if (HOST_AUTHENTICATION_FEATURE_SUPPORTED == 1)
		ret = auths_exe_host_authentication();
		if (APP_HA_SUCCESS != ret) {
			PRINT_C(RED, "Host Authentication failed. ret=0x%x\r\n",ret);
			//return;
		} else {
			PRINT("Host Authenticated\r\n");
		}
#endif
	PRINT("After Reset.\r\n");
	ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_FEAT_STS_1, rd_data, 1);
	if(SDK_INTERFACE_SUCCESS != ret){
		PRINT("Read AUTHS_SFR_LSC_KILL_FEAT_STS_1 failed!! ret=0x%x\r\n", ret);
		return;
	}
	PRINT("LSC_KILL_FEAT_STATUS_1 = 0x%.2X\r\n", rd_data[0]);
	if(lsc_number == 0){
		ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_FEAT_STS_2, rd_data, 1);
		if(SDK_INTERFACE_SUCCESS != ret){
			PRINT("Read AUTHS_SFR_LSC_KILL_FEAT_STS_2 failed!! ret=0x%x\r\n", ret);
			return;
		}
		PRINT("LSC_KILL_FEAT_STATUS_2 = 0x%.2X\r\n", rd_data[0]);
	}
	
	
	// LSC_Reset_STS
	ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_ACT_STS_2, rd_data, 1);
	if(SDK_INTERFACE_SUCCESS != ret){
		PRINT("Read AUTHS_SFR_LSC_KILL_ACT_STS_2 failed!! ret=0x%x\r\n", ret);
		return;
	}
	PRINT("LSC_KILL_ACT_STATUS_2 = 0x%.2X\r\n", rd_data[0]);
	bit_position=0;
	if(lsc_number == 0){ 
		bit_position = BIT_LSC1_RESET_STS;
	}
	else if(lsc_number == 1) {
		bit_position = BIT_LSC2_RESET_STS;
	}
	else if(lsc_number == 2) {
		bit_position = BIT_LSC3_RESET_STS;
	}
	else if(lsc_number == 3) {
		bit_position = BIT_LSC4_RESET_STS;
	}

	if(((rd_data[0] >> bit_position) & 0x01) != 0x01){
		PRINT("LSC%d_Reset_STS is not set\r\n", lsc_number+1);
	}
}

void test_Lsc2AutoDec()
{
	uint16_t ret;
	//uint8_t rd_data[UID_BYTE_LEN];
	uint32_t ul_lsc;
	uint32_t ul_lsc_1;
	uint16_t lsc_decVal;

	// Read LSC decreased value
	ret = auths_get_lsc_decvalue(&lsc_decVal);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read decreased value ret=0x%x\r\n", ret);
		return;
	}else{
		PRINT("Info: Decreased value 0x%.8X\r\n", lsc_decVal);
	}
	// Read LSC2 before ECC
	ret = auths_get_lsc_value(1,&ul_lsc);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC2, ret=0x%x\r\n", ret);
		return;
	}else{
		PRINT("Before decrease, LSC2 = 0x%.8X\r\n", ul_lsc);
	}

	PRINT("Run Authentication.\r\n");
	ret = auths_exe_ecc(0,0);
	if(EXE_SUCCESS != ret){
		PRINT("Error: Authentication failed, ret=0x%x\r\n", ret);
		return;
	}

	delay_ms(NVM_PROGRAMMING_TIME);
	delay_ms(NVM_PROGRAMMING_TIME);

	// Read LSC2 after ECC
	ret = auths_get_lsc_value(1,&ul_lsc_1);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC2, ret=0x%x\r\n", ret);
		return;
	} else {
		PRINT("After decreasing, LSC2 = 0x%.8X\r\n",ul_lsc_1);
	}

	if(ul_lsc < lsc_decVal){
		if(ul_lsc_1 != 0){
			PRINT("Mistmatch: LSC2 not 0\r\n");
		}
	}else{
		if((ul_lsc_1 + lsc_decVal) != ul_lsc){
			PRINT("Error: Decrease LSC2 failed (%d, %d)\r\n",(ul_lsc_1 + lsc_decVal),  ul_lsc);
		}
	}
}
//自减计数1
void test_Lsc1AutoDec()
{
	uint16_t ret;
	uint8_t rd_data;
	uint32_t ul_lsc;
	uint32_t ul_lsc_1;
    uint8_t ub_RdTimeOut = 50;
    uint8_t ubData;
    uint16_t lsc_decVal;
    uint8_t data[4]={0x1, 0x2, 0x3, 0x4};
    uint8_t bytetowrite=4;
    uint8_t nvm_page =0;

	// check auto decrease enable bit set
	ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_FEAT_STS_2, &rd_data, 1);
	if(SDK_INTERFACE_SUCCESS != ret){
		PRINT("Error: Read AUTHS_SFR_LSC_KILL_FEAT_STS_2 ret=0x%x\r\n", ret);
		return;
	}
	if(((rd_data >> BIT_LSC_1_AU_EN_STS) & 0x01) == 0x01){
		//PRINT("LSC_1_AU_EN_STS is already set!!\r\n");
	}
	else{
		PRINT("set LSC_1_AU_EN.\r\n");
		ret =  auths_set_lsc1_autodec();
        if(APP_LSC_ENABLE_AUTODEC != ret){
			PRINT("Error: set LSC_1_AU_EN ret=0x%x\r\n", ret);
			return;
        }
	}
	delay_ms(NVM_PROGRAMMING_TIME);
	ret = auths_get_lsc_value(0, &ul_lsc);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read LSC1 ret=0x%x\r\n",ret);
		return;
	}else{
		PRINT("Before decrease, LSC1 = 0x%.8X\r\n",ul_lsc);
	}

	ret = auths_write_nvm(nvm_page, data, bytetowrite);
	if(APP_NVM_SUCCESS != ret){
		PRINT("Error: Write NVM, ret=0x%x\r\n", ret);
		return;
	}

	delay_ms(NVM_PROGRAMMING_TIME);
	
	if(auths_get_nvm_lock_status(nvm_page) == APP_NVM_PAGE_LOCKED){
		PRINT("NVM address is locked \r\n");
		return;
	}
	do{
		ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_ACT_STS_2, &ubData,1);
		if(SDK_INTERFACE_SUCCESS !=  ret){
			PRINT("Error: Read AUTHS_SFR_LSC_KILL_ACT_STS_2, ret=0x%x\r\n", ret);
			return;
		}
		if(ub_RdTimeOut == 0){
			return;
		}
		ub_RdTimeOut -- ;
	}while( ((ubData >> BIT_LSC_DEC_1_STS) & 0x01) != 0x00 );
	
	delay_ms(NVM_PROGRAMMING_TIME);

	ret = auths_get_lsc_value(0,&ul_lsc_1);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Get LSC1 value ret=0x%x\r\n", ret);
		return;
	} else {
		PRINT("After decrease, LSC1 = 0x%.8X\r\n", ul_lsc_1);
	}

	// Read LSC decreasing value
	ret = auths_get_lsc_decvalue(&lsc_decVal);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Read decreasing, ret=0x%x\r\n", ret);
		return;
	} else {
		PRINT("decrease value is 0x%.8X\r\n", lsc_decVal);
	}

	if(ul_lsc < lsc_decVal){
		if(ul_lsc_1 != 0){
			PRINT("Error: LSC1 not 0\r\n");
		}
	}else{
		if((ul_lsc_1 + lsc_decVal) != ul_lsc){
			PRINT("Mismatch: Decrease LSC1 (%d, %d)\r\n", (ul_lsc_1 + lsc_decVal),ul_lsc);
		}
	}
}
